/**
 * 
 */
package com.wxpay.controller;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.KeyStore;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alipay.service.interfaced.AlipayInManager;
import com.business.service.interfaced.EntertainmentInManager;
import com.business.service.interfaced.StandardInManager;
import com.business.service.interfaced.impl.HighEntertainInService;
import com.honour.service.interfaced.CartInManager;
import com.honour.service.interfaced.OrderManager;
import com.honour.service.interfaced.SortInManager;
import com.system.common.OrderEnum;
import com.system.common.PayType;
import com.system.controller.base.BaseController;
import com.system.property.WXProperty;
import com.system.util.AppUtil;
import com.system.util.DateUtil;
import com.system.util.PageData;
import com.system.util.Tools;
import com.wxpay.util.PayCommonUtil;

 

/**
 * @author zhanglingbing
 * @date 2018年5月4日
 */
@Controller
@RequestMapping(value = "/weixinpay")
public class WeiXinPayController extends BaseController {
	
	@Resource(name="standardInService")
	private StandardInManager standardInService;
	
	@Resource(name = "cartInService")
	private CartInManager cartInService;
	
	@Resource(name="highEntertainInService")
	private HighEntertainInService highEntertainInService;
	
	@Resource(name = "orderService")
	private OrderManager orderService;
	
	@Resource(name = "alipayInManager")
	private AlipayInManager alipayInService;
	
	@Resource(name="entertainmentInService")
	private EntertainmentInManager entertainmentInService;
	
	@Resource(name="sortinService")
	private SortInManager sortinService;
	
	
	//private static Logger logger = LoggerFactory.getLogger(WeiXinPayController.class);
	     
	     String randomString = PayCommonUtil.getRandomString(32);
	     
	     
	     
	     
	 
	     /**
	      * 微信支付回调地址
	       * @Description
	       * @Author zhaozhenhua
	       * @date   2018年5月11日
	       * @param pd
	       * @return
	       * @throws Exception
	      */
	     @RequestMapping(value = "/success")
	     public String wxpaySucc(HttpServletRequest request){
	    	 logger.info("微信支付回调");
	    	 
	    	 //商户处理后同步返回给微信参数：
	    	 String xmlResultSuccess = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
	    	 String xmlResultFailure = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
	    	 
	    	 SortedMap<String, Object> params = null;
			try {
				InputStream inStream = request.getInputStream();
				ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
				byte[] buffer = new byte[1024];
				int len = 0;
				while ((len = inStream.read(buffer)) != -1) {
					outSteam.write(buffer, 0, len);
				}
				String resultxml = new String(outSteam.toByteArray(), "utf-8");
				params =  PayCommonUtil.doXMLParse(resultxml);
				logger.info("微信回调的信息:解析XML得到key:value");
				for (Object b : params.keySet()) {
					logger.info("key="+b+":"+"value="+params.get(b));
				}
				outSteam.close();
				inStream.close();
			} catch (Exception e) {
				e.printStackTrace();
				logger.info("回调xml解析失败");
			}
			//验证签名
			 boolean signVerified = PayCommonUtil.checkWXSign(params);
			 logger.info("验证签名:"+signVerified);
	         if (!signVerified) {
	             // 支付失败
	        	 //将订单状态设置为待支付
	        	 
	        	 return xmlResultFailure;
	         } else {
		 	        String return_code = (String) params.get("return_code");//状态
		 	        String out_trade_no = (String) params.get("out_trade_no");//订单号
		 	        String ORDERTYPE = (String) params.get("attach");//商家数据包
		 	        System.out.println("订单号out_trade_no:"+out_trade_no);
		 	        
		 	        //防止微信重复通知
		 	        PageData pd = new PageData();
		 	        pd.put("ORDERNUMBER", out_trade_no);
		 	        try {
						PageData payInfo = alipayInService.getPayInfo(pd);
						if(payInfo != null){
							return xmlResultSuccess;
						}
					} catch (Exception e1) {
						e1.printStackTrace();
					}
		 	        
		 			if (return_code.equals("SUCCESS")) {
		 				if (out_trade_no != null) {
		 					//处理订单逻辑
		 					logger.info("微信手机支付回调成功订单号:{}"+out_trade_no);
		 					//转化时间格式
							String date = params.get("time_end").toString();
						    Date stringToDate = com.system.util.DateUtil.stringToDate(date);
						    String time_end = com.system.util.DateUtil.dateToString(stringToDate);
						    PageData order = new PageData();
		 				
							try {
								switch (ORDERTYPE) {
								case "1"://订单类型为美食
									logger.info("TODO 支付通知(微信后台的回调通知)---美食订单");
									order = entertainmentInService.getFoodOrderByNum(pd);
									pd.put("ORDERPAYTIME", time_end);//交易创建时间
								    pd.put("ORDERSTATUS", "0040002");//待使用
									pd.put("HONOURUSER_ID", order.get("HONOURUSER_ID"));
									pd.put("ORDEROTHERNUM", params.get("transaction_id"));//微信支付订单号
									sortinService.updFoodOrderStatus(pd);
									//插入订单支付信息
									addWXPayInfo(pd,params,order,time_end);
									return xmlResultSuccess;
								case "2"://订单类型为酒店
									logger.info("TODO 支付通知(微信后台的回调通知)---酒店订单");
									order = entertainmentInService.getHotelOrderByNum(pd);
									pd.put("ORDERPAYTIME", time_end);//交易创建时间
								    pd.put("ORDERSTATUS", "0040002");//待使用
									pd.put("HONOURUSER_ID", order.get("HONOURUSER_ID"));
									pd.put("ORDEROTHERNUM", params.get("transaction_id"));//微信支付订单号
									sortinService.updHotelOrderStatus(pd);
									//插入订单支付信息
									addWXPayInfo(pd,params,order,time_end);
									return xmlResultSuccess;
								case "3"://订单类型为KTV
									logger.info("TODO 支付通知(微信后台的回调通知)---KTV订单");
									order = entertainmentInService.getKTVOrderByNum(pd);
									pd.put("ORDERPAYTIME", time_end);//交易创建时间
								    pd.put("ORDERSTATUS", "0040002");//待使用
									pd.put("HONOURUSER_ID", order.get("HONOURUSER_ID"));
									pd.put("ORDEROTHERNUM", params.get("transaction_id"));//微信支付订单号
									sortinService.updKTVOrderStatus(pd);
									//插入订单支付信息
									addWXPayInfo(pd,params,order,time_end);
									return xmlResultSuccess;
								case "4"://订单类型为酒吧
									logger.info("TODO 支付通知(微信后台的回调通知)---酒吧订单");
									order = entertainmentInService.getBarOrderByNum(pd);
									pd.put("ORDERPAYTIME", time_end);//交易创建时间
								    pd.put("ORDERSTATUS", "0040002");//待使用
									pd.put("HONOURUSER_ID", order.get("HONOURUSER_ID"));
									pd.put("ORDEROTHERNUM", params.get("transaction_id"));//微信支付订单号
									sortinService.updBarOrderStatus(pd);
									//插入订单支付信息
									addWXPayInfo(pd,params,order,time_end);
									return xmlResultSuccess;
								case "5"://订单类型为马术
									logger.info("TODO 支付通知(微信后台的回调通知)---马术订单");
									order = highEntertainInService.getHighOrderByNo(pd);
									updHighOrder(pd, params, order, time_end);
									return xmlResultSuccess;
								case "6"://订单类型为游艇
									logger.info("TODO 支付通知(微信后台的回调通知)---尊购商品订单");
									order = highEntertainInService.getHighOrderByNo(pd);
									updHighOrder(pd, params, order, time_end);
									return xmlResultSuccess;
								case "7"://订单类型为豪车
									logger.info("TODO 支付通知(微信后台的回调通知)---豪车订单");
									order = highEntertainInService.getHighOrderByNo(pd);
									updHighOrder(pd, params, order, time_end);
									return xmlResultSuccess;
								case "8"://订单类型为飞机
									logger.info("TODO 支付通知(微信后台的回调通知)---飞机订单");
									order = highEntertainInService.getHighOrderByNo(pd);
									updHighOrder(pd, params, order, time_end);
									return xmlResultSuccess;
								case "9"://订单类型为高尔夫
									logger.info("TODO 支付通知(微信后台的回调通知)---高尔夫订单");
									order = highEntertainInService.getHighOrderByNo(pd);
									updHighOrder(pd, params, order, time_end);
									return xmlResultSuccess;
								case "50"://订单类型为尊购商品
									//查询订单,修改子订单表状态，减库存,加商品销售数量,修改订单表支付时间
									logger.info("TODO 支付通知(微信后台的回调通知)---尊购商品订单");
									order = orderService.getByUserIdAndOrderNo(pd);
									order.put("ORDERSTATUS", "待发货");
									orderService.updateOrderStatus(order);
									
									//从购物车中移除商品
									order.put("CHECKED", 1);
									List<PageData> cartList = cartInService.selectProductByUserIdAndChecked(order);
									//将购物车中的商品的规格id和数量放入mapCart中
									Map<String, Object> mapCart = new HashMap<>();
									for (PageData cart : cartList) {
										mapCart.put(cart.getString("STANDARD_ID"), cart.get("QUANTITY"));
										cartInService.delete(cart);
									}
									
									List<PageData> stockByNum = orderService.getStockByNum(order);
									for (PageData p : stockByNum) {
										Integer PRO_STOCK = p.getInterger("PRO_STOCK");
										PRO_STOCK = PRO_STOCK-(Integer)mapCart.get(p.getString("STANDARD_ID"));
										p.put("PRO_STOCK", PRO_STOCK);
										standardInService.edit(p);
									}
									
									order.put("PAY_TIME", params.get("notify_time"));
									order.put("PAYTYPE", 1);
									orderService.updateOrder(order);
									//插入订单支付信息
									addWXPayInfo(pd,params,order,time_end);
									return xmlResultSuccess;
								default:
									break;
								}
							} catch (Exception e) {
								e.printStackTrace();
							}
		 				}
		 			}else{
		 				logger.info("微信手机支付回调失败订单号:{}"+out_trade_no);
		 				return xmlResultFailure;
		 			}
	         }
			return null;
	     }
	     
	     
	 /**
	  * 添加微信订单支付信息
	   * @Description
	   * @Author zhaozhenhua
	   * @date   2018年5月11日
	   * @param pd
	   * @param params
	   * @param order
	   * @param time_end
	  */
	 public void addWXPayInfo(PageData pd,SortedMap<String, Object> params,PageData order,String time_end){
		pd.put("PAYINFO_ID", this.getSnowId());
		pd.put("PLATFORM_NUMBER", params.get("transaction_id"));//微信支付订单号
		pd.put("PLATFORM_STATUS", "success");
		pd.put("PAY_PLATFORM", PayType.WECHAT.getCode());
		pd.put("ORDERNUMBER", params.get("out_trade_no"));//商户订单号
		pd.put("CREATE_TIME", time_end); //支付完成时间
		pd.put("HONOURUSER_ID", order.get("HONOURUSER_ID"));
		pd.put("ORDERMONEY", params.get("total_fee"));//总金额
		pd.put("ORDERTYPE", params.get("attach"));//订单类型
		try {
			alipayInService.addPayInfo(pd);
		} catch (Exception e) {
			e.printStackTrace();
		}
	 }   
	 
	 
	 /**
	  * 修改高端特权订单状态
	   * @Description
	   * @Author zhaozhenhua
	   * @date   2018年5月15日
	   * @param pd
	   * @return
	   * @throws Exception
	  */
	 public void updHighOrder(PageData pd,SortedMap<String, Object> params,PageData order,String time_end){
		    pd.put("ORDERPAYTIME", time_end);//交易创建时间
			pd.put("ORDERSTATUS", "0040002");//待使用
			pd.put("HIGHENTERORDER_ID", order.get("HIGHENTERORDER_ID"));
			pd.put("ORDEROTHERNUM", params.get("transaction_id"));//微信支付订单号
			try {
				highEntertainInService.updHighOrder(pd);
				//插入订单支付信息
				addWXPayInfo(pd,params,order,time_end);
			} catch (Exception e) {
				e.printStackTrace();
			}
		 }    
	 
	/**
	 * 微信退款接口
	  * @Description
	  * @Author zhaozhenhua
	  * @date   2018年5月21日
	  * @param pd
	  * @return
	  * @throws Exception
	 */
		 @ResponseBody
		 @RequestMapping(value = "wxPayRefund")
		 public Object wxpayRefundRequest(){
			 logBefore(logger, "微信退款接口");
			 Map<String,Object> map = new HashMap<String,Object>();
			 PageData pd = new PageData();
			 pd = this.getPageData();
			 String result = "00";
			 FileInputStream inputStream = null;
			 try{
					if(Tools.checkKey("WXPAYREFUND", pd.getString("FKEY"))){	//检验请求key值是否合法
						if(AppUtil.checkParam("aliPayRefund", pd)){	//检查参数
							//判断是否为重复操作
							PageData refundByNum = alipayInService.getRefundByNum(pd);
							if(refundByNum!=null){
								result = "01";
								map.put("pd", "已申请退款");
								return AppUtil.returnObject(new PageData(), map);
							}
							
							//读取证书
							String path = this.getClass().getClassLoader().getResource("/").getPath();
							String certPath = path + WXProperty.get("CERT_PATH");
							logger.info("证书路径certPath:"+certPath);
							KeyStore keyStore = KeyStore.getInstance("PKCS12");
						    inputStream = new FileInputStream(new File(certPath));
							keyStore.load(inputStream, WXProperty.get("MCH_ID").toCharArray());
							
							//先生成自己系统退款订单
							String REFUND_ID = this.getSnowId();
							pd.put("REFUND_ID", REFUND_ID);
							pd.put("REFUND_TIME", DateUtil.getTime());
							pd.put("PAY_PLATFORM", PayType.WECHAT.getCode());
							pd.put("REFUND_FEE", pd.get("ORDERMONEY"));
							alipayInService.addRefundInfo(pd);
							
							//退款请求参数封装
							SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();  
					         parameterMap.put("appid", WXProperty.get("APP_ID"));  
					         parameterMap.put("mch_id", WXProperty.get("MCH_ID"));  
					         parameterMap.put("nonce_str", PayCommonUtil.getRandomString(32));  
					         parameterMap.put("transaction_id", pd.get("ORDEROTHERNUM"));//微信订单号
					         parameterMap.put("out_trade_no", pd.get("ORDERNUMBER"));//商户订单号
					         parameterMap.put("out_refund_no", REFUND_ID);//商户退款单号
					         //支付金额
							 BigDecimal totalAmount =  new BigDecimal((String)pd.get("ORDERMONEY"));
					         BigDecimal total = totalAmount.multiply(new BigDecimal(100));  
					         parameterMap.put("refund_fee", total);  //退款金额
					         parameterMap.put("total_fee", total);  //订单金额
					         parameterMap.put("refund_fee_type", "CNY");  //退款货币种类
					         parameterMap.put("sign_type", "MD5");
					         String sign = PayCommonUtil.createSign("UTF-8", parameterMap) ;
					         parameterMap.put("sign", sign);
					         
					         String requestXML = PayCommonUtil.getRequestXml(parameterMap);
					         System.out.println("【转换为xml格式的参数】   "+requestXML);  
					         
					        // Trust own CA and all self-signed certs  
				            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WXProperty.get("MCH_ID").toCharArray()).build();  
				            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
				                    sslcontext,
				                    new String[]{"TLSv1"},
				                    null,
				                    SSLConnectionSocketFactory.getDefaultHostnameVerifier());
				            CloseableHttpClient httpclient = HttpClients.custom()  
				                    .setSSLSocketFactory(sslsf).build();  
				            HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");  
				            
				            StringEntity se = new StringEntity(requestXML);  
				            httppost.setEntity(se);  

				            System.out.println("Executing request " + httppost.getRequestLine());

				            CloseableHttpResponse response = httpclient.execute(httppost);
				            HttpEntity entity = response.getEntity();   
					         
				            InputStream in = entity.getContent();
				            SortedMap<String, Object> m = new TreeMap<>();
				            try {
				    			SAXBuilder builder = new SAXBuilder();
				    			Document doc = builder.build(in);
				    			Element root = doc.getRootElement();
				    			List list = root.getChildren();
				    			Iterator it = list.iterator();
				    			while (it.hasNext()) {
				    				Element e = (Element) it.next();
				    				String k = e.getName();
				    				String v = "";
				    				List children = e.getChildren();
				    				if (children.isEmpty()) {
				    					v = e.getTextNormalize();
				    				} else {
				    					v = PayCommonUtil.getChildrenText(children);
				    				}

				    				m.put(k, v);
				    			}

				    			// 关闭流
				    			in.close();
				    		} catch (Exception e1) {
				    			e1.printStackTrace();
				    		}
					         
					         
					         
					         for (Object key  : m.keySet()) {
								System.out.println("请求返回的内容：key="+key+";value="+m.get(key));
							 }
					         
					         
							 String returnCode = (String) m.get("return_code");
					         System.out.println("【返回内容 returnCode  】   "+returnCode); 
					         
							 if (returnCode.equals("SUCCESS")) {
								 System.out.println("调用成功");
								 pd.put("REFUND_PAY_TIEM", DateUtil.getTime());
							     alipayInService.updRefund(pd);
							     //修改订单的状态
							     String ORDERTYPE = pd.getString("ORDERTYPE");
							     switch (ORDERTYPE) {
								case "1":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									sortinService.updFoodOrderStatus(pd);
									break;
								case "2":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									sortinService.updHotelOrderStatus(pd);
									break;
								case "3":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									sortinService.updKTVOrderStatus(pd);
									break;
								case "4":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									sortinService.updBarOrderStatus(pd);
									break;
								case "5":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									highEntertainInService.updHighOrder(pd);
									break;
								case "6":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									highEntertainInService.updHighOrder(pd);
									break;
								case "7":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									highEntertainInService.updHighOrder(pd);
									break;
								case "8":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									highEntertainInService.updHighOrder(pd);
									break;
								case "9":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									highEntertainInService.updHighOrder(pd);
									break;
								case "10":
									pd.put("ORDERSTATUS", OrderEnum.REFUND.getCode());
									highEntertainInService.updHighOrder(pd);
									break;
								case "50":
									pd.put("ORDERSTATUS", "已退款");
					            	orderService.updateOrderStatus(pd);
									break;
									
								default:
									break;
								}
							     result = "01";
							     map.put("pd", "已申请退款");
							 } else {
								 logger.info("退款失败");
								 map.put("pd", "退款失败");
								 result = "02";
							 }
						}else {
							result = "03";
						}
					}else{
						result = "05";
					}
				}catch (Exception e){
					logger.error(e.toString(), e);
				}finally{
					try {
						map.put("result", result);
						logAfter(logger);
						if(inputStream!=null){
							inputStream.close();
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			return AppUtil.returnObject(new PageData(), map);
			
		 }
		 
		 
	 
}